#include "CEngine.h"



CEngine::~CEngine()
{
}
CEngine::CEngine()
{
	hInstance =0;
	hWND      =0;
	direct3d  =0;
	device    =0;
	m_Width   =0;
	m_Height  =0;
	m_Windowed=0;
}
bool CEngine::SetupWindow()
{
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style              = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc        = (WNDPROC)WndProc;
	wcex.cbClsExtra         = 0;
	wcex.cbWndExtra         = 0;
	wcex.hInstance          = hInstance;
	wcex.hIcon               = 0;
	wcex.hCursor            = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground      = NULL;
	wcex.lpszMenuName       = NULL;
	wcex.lpszClassName      = "Game Window";
	wcex.hIconSm            = 0;	
	RegisterClassEx(&wcex);

	hWND= CreateWindow(  "Game Window","Game Window",WS_EX_TOPMOST|WS_POPUP,
	CW_USEDEFAULT,CW_USEDEFAULT,m_Height,m_Width,
	NULL,NULL,hInstance,NULL);
	
	if (!hWND)return false;
	
	//ShowWindow(hWND, SW_SHOW);
	//UpdateWindow(hWND);
	
	return true;
}
bool CEngine::Setup(int Width,int Height,bool Windowed)
{
	m_Width =Width;
	m_Height=Height;
	m_Windowed=Windowed;

	SetupWindow();

	if(FAILED(direct3d=Direct3DCreate9(D3D_SDK_VERSION))){
		::MessageBoxA(hWND,"Direct3DCreate9","ERROR",MB_OK);
		return false;
	}

	D3DPRESENT_PARAMETERS m_d3dpp;
	ZeroMemory(&m_d3dpp,sizeof(m_d3dpp));
	m_d3dpp.hDeviceWindow          = hWND;
	m_d3dpp.Windowed               = m_Windowed;
	m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
	m_d3dpp.BackBufferFormat       = D3DFMT_X8R8G8B8;
	m_d3dpp.EnableAutoDepthStencil = TRUE;
	m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	m_d3dpp.BackBufferWidth        = m_Width;
	m_d3dpp.BackBufferHeight       = m_Height;
	m_d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;
	
	
	if(FAILED(direct3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWND,
                          D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                          &m_d3dpp, &device ))){
		::MessageBoxA(hWND,"DEVICE CREATION ERROR","CreateDevice",MB_OK);
		return false;
	}
	device->SetRenderState(D3DRS_AMBIENT,RGB(255,255,255));
	device->SetRenderState(D3DRS_LIGHTING,FALSE);
	device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
	device->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);
	device->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
	
	
	SetupFps();

	return true;
}
bool CEngine::SetupFps()
{
	HRESULT hr;
	HDC hDC;
	int nHeight;
	int nPointSize = 13;
	hDC = GetDC( NULL );
	nHeight = -( MulDiv( nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72 ) );
	ReleaseDC( NULL, hDC );
	hr = D3DXCreateFont(Engine->GetDevice(),nHeight, 0, FW_BOLD, 0, FALSE, 
		                 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY , 
		                 DEFAULT_PITCH | FF_DONTCARE, TEXT("Modern"), 
		               &m_FpsFont);  
	return true;
}
void CEngine::BEGINRENDER(int Red,int Green,int Blue)
{
	device->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(Red,Green,Blue),1.0f,0);
	device->BeginScene();
}
void CEngine::ENDRENDER()
{
	device->EndScene();
	device->Present(NULL,NULL,NULL,NULL);
}
void CEngine::ShowFPS()
{
	static int iFramesPerSecond = 0;
	static int iTempFramesCounter = 0;
	unsigned int dwTicksNow = GetTickCount();
	static unsigned int dwPastTicks = 0;
	if( dwPastTicks < dwTicksNow )
	{
		dwPastTicks = dwTicksNow + 1000; // 1000 milliseconds = 1 second
		iFramesPerSecond = iTempFramesCounter;
		iTempFramesCounter = 0;
	}
	iTempFramesCounter++;
	char szbuff[200];
	wsprintfA(szbuff, "Frames Per Second: %d", iFramesPerSecond);
	RECT destRect1;
	SetRect( &destRect1, 15, 15, 0, 0 );
	m_FpsFont->DrawTextA( NULL,szbuff, -1, &destRect1, DT_NOCLIP, 
	                   D3DXCOLOR(112 ,128, 144 , 1.0f) );
}
void CEngine::RenderSolid()
{
	device->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
}
void CEngine::RenderWired()
{
	device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
}
void CEngine::CleanUP()
{
	device->Release();
	m_FpsFont->Release();
	direct3d->Release();
}
int CEngine::EnterLoop(bool SetupScene(),void RenderScene(),void CleanScene())
{
	if(FAILED(SetupScene()))
		return false;
	MSG msg;
	while(true)
	{
		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		if(msg.message==WM_QUIT)
			break;

		RenderScene();
	}	
	CleanScene();
	return msg.wParam;
}
void CEngine::SetProjection(float Fov,float Near,float Far)
{
	D3DXMATRIX m_Projection;
	D3DXMatrixPerspectiveFovLH(&m_Projection,Fov,float(m_Width/m_Height),Near,Far);
	device->SetTransform(D3DTS_PROJECTION, &m_Projection);
}
void CEngine::SetBasicCamera(D3DXVECTOR3 Eye,D3DXVECTOR3 Look,D3DXVECTOR3 Up)
{	
	D3DXVECTOR3 m_EyePos(Eye.x, Eye.y, Eye.z);
	D3DXVECTOR3 m_TargetPos(Look.x,Look.y,Look.z);
	D3DXVECTOR3 m_UpVector(Up.x,Up.y,Up.z);
	
	D3DXMATRIXA16 MatrixView;
	D3DXMatrixLookAtLH(&MatrixView, &m_EyePos, &m_TargetPos, &m_UpVector);
	device->SetTransform(D3DTS_VIEW, &MatrixView);
}
void CEngine::SetTransform(D3DTRANSFORMSTATETYPE Type,D3DXMATRIX *Temp)
{
	device->SetTransform(Type,Temp);
}
void CEngine::SetWorldTransform(D3DXMATRIX *Temp)
{
	device->SetTransform(D3DTS_WORLD,Temp);
}
void CEngine::SetTranslation(D3DXMATRIX *Temp,float x,float y,float z)
{
	D3DXMatrixTranslation(Temp,x,y,z);
}
void CEngine::LoadTexture(LPDIRECT3DTEXTURE9 *Texture,std::string filename)
{
	D3DXCreateTextureFromFile(device,filename.c_str(),Texture);
}
int CEngine::ShowMouse(bool Visible)
{
	ShowCursor(Visible);
	return 1;
}
int CEngine::GetRandom(int Min,int Max)
{
	return(rand()%(Max-Min)+Min);
}
double CEngine::ConvertToDegree(double Radians)
{
	return Radians*180/PI;	
}
double CEngine::ConvertToRadian(double Degree)
{
	return Degree/PI*180;
}
float CEngine::GetDistance(D3DXVECTOR3 Player,D3DXVECTOR3 Object)
{
	float distanceX=Object.x-Player.x;
	float distanceY=Object.y-Player.y;
	float distanceZ=Object.z-Player.z;

	float MulX=distanceX*distanceX;
	float MulY=distanceY*distanceY;
	float MulZ=distanceZ*distanceZ;

	float result=MulX+MulY+MulZ;

	return sqrt(result);
}
LRESULT CALLBACK CEngine::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        switch (message)
        {
		case WM_DESTROY:
			PostQuitMessage(0);
			break;		
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
}